package com.pkk.cloud.support.oauth2.security.access.configuration;

import com.pkk.cloud.support.oauth2.client.url.properties.IgnoreUrlProperties;
import com.pkk.cloud.support.oauth2.security.access.condition.EnableResourceServerCondition;
import com.pkk.cloud.support.oauth2.security.access.condition.EnableWebSecurityCondition;
import com.pkk.cloud.support.oauth2.security.access.entrypoint.AuthExceptionEntryPoint;
import com.pkk.cloud.support.oauth2.security.access.handler.AuthAccessDeniedHandler;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;

/**
 * @Description: 忽略资源配置的设置
 * <p>
 * 正常情况下WebSecurityConfigurerAdapter的拦截优先于ResourceServerConfigurerAdapter 某些情况下如果需要ResourceServerConfigurerAdapter的拦截优先于WebSecurityConfigurerAdapter需要在配置文件中添加
 * security.oauth2.resource.filter-order=99
 * <p>
 * @EnableWebSecurity 注解标注的security类创建了一个WebSecurityConfigurerAdapter，且自带了硬编码的order=3,使用spring security而不是auth，即http保护
 * @return:
 * @Author: peikunkun
 * @Date: 2020/3/19 0019 下午 4:08
 */
@Slf4j
@Configuration
public class SecurityAccessAutoConfiguration {

  @Autowired
  private IgnoreUrlProperties ignoreUrlProperties;


  /**
   * @Description: ResourceServerConfigurerAdapter是默认情况下spring security oauth2的http配置
   * <p>
   * SecurityProperties.ACCESS_OVERRIDE_ORDER - 1;是大于1的,即WebSecurityConfigurerAdapter的配置的拦截要优先于ResourceServerConfigurerAdapter，优先级高的http配置是可以覆盖优先级低的配置的
   *
   * <p>------------------------------
   * <p>此处是资源、授权中心服务器的资源权限配置拦截设置
   * <p>------------------------------
   * @Author: peikunkun
   * @Date: 2020/3/22 0022 下午 8:34
   */
  @Configuration
  @NoArgsConstructor
  @Conditional(EnableResourceServerCondition.class)
  private class ResourceServerSecurityAccessConfiguration extends ResourceServerConfigurerAdapter {

    //@formatter:off
    //TODO 待实现根据配置文件实现动态变动
    @Override
    public void configure(HttpSecurity http) throws Exception {
      http.csrf().disable();
      if (ignoreUrlProperties.isEnable() && ignoreUrlProperties.getUrls().size() > 0) {
        //如果存在过滤的请求设置为全部不限制
        http.authorizeRequests().antMatchers(ignoreUrlProperties.getUrls().toArray(new String[ignoreUrlProperties.getUrls().size()])).permitAll();
      }
      //每次请求安全拦截
      http.authorizeRequests().anyRequest().authenticated().filterSecurityInterceptorOncePerRequest(false);
      log.info("Security Access Control is enabled on Resource Server Application");
    }

    /**
     * @Description: 配置认证失败的异常端点的操作
     * @Param: resources
     * @return: void
     * @Author: peikunkun
     * @Date: 2020/3/22 0022 下午 9:17
     */
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
      resources.authenticationEntryPoint(new AuthExceptionEntryPoint()).accessDeniedHandler(new AuthAccessDeniedHandler());
    }
    //@formatter:on
  }

  /**
   * @Description: 配置忽略的接口url地址配置【WebSecurityConfigurerAdapter适配器用于通过会话对用户进行身份验证（如表单登录）】
   * WebSecurityConfigurerAdapter是默认情况下spring security的http配置
   * <p>
   * SecurityProperties.ACCESS_OVERRIDE_ORDER - 1;是大于1的,即WebSecurityConfigurerAdapter的配置的拦截要优先于ResourceServerConfigurerAdapter，优先级高的http配置是可以覆盖优先级低的配置的
   *
   *
   * <p>------------------------------
   * <p>此处是资源、授权中心服务器的资源权限配置拦截设置
   * <p>------------------------------
   * @Author: peikunkun
   * @Date: 2020/3/21 0021 下午 11:54
   */
  @Configuration
  @NoArgsConstructor
  @Conditional(EnableWebSecurityCondition.class)
  private class WebSecurityAccessConfiguration extends WebSecurityConfigurerAdapter {

    //TODO 待实现根据配置文件实现动态变动
    //@formatter:off
    @Override
    protected void configure(HttpSecurity http) throws Exception {
      //禁止跨域
      http.csrf().disable();
      //是否启用忽略配置的开关
      if (ignoreUrlProperties.isEnable() && ignoreUrlProperties.getUrls().size() > 0) {
        //配置请求的过滤器
        http.authorizeRequests().antMatchers(ignoreUrlProperties.getUrls().toArray(new String[ignoreUrlProperties.getUrls().size()])).permitAll();
      }
      http.authorizeRequests().anyRequest().authenticated().filterSecurityInterceptorOncePerRequest(false);
      log.info("Security Access Control is enabled on Web Application");
    }
    //@formatter:on
  }

}
